using UnityEngine;
using System.Collections;

public class BSP_Dungeon
{
	public int globi = 0;
	public BSP_Nodes root = new BSP_Nodes();
	public BSP_Nodes leaf;
	public Line splitLine = new Line();
	public BSP_Nodes[] leafNodes = new BSP_Nodes[100];
	public BSP_Nodes[] oldNodes = new BSP_Nodes[100];
	public BSP_Parameters parameter;
	public bool displaySplits = true;
	public BSP_Rectangle[] rooms = new BSP_Rectangle[100];
	public Tracker tracker;
	public BSP_Dungeon dungeon;
	public int[] roomOrder = new int[100];
	public int j;
	public bool vertical = false;
	BSP_Rectangle myRectangle = new BSP_Rectangle();
	private BSP_Parameters param;
	
	public BSP_Dungeon()
	{
		this.roomOrder[0] = new int();
		this.roomOrder[0] = 0;
		this.rooms[0] = new BSP_Rectangle();
		this.leafNodes[0] = new BSP_Nodes();
		this.oldNodes[0] = new BSP_Nodes();
		this.parameter = new BSP_Parameters();
		this.param = parameter;
		this.oldNodes[0].leftChild = new BSP_Nodes();
		this.oldNodes[0].rightChild = new BSP_Nodes();
	}
	public BSP_Dungeon(BSP_Parameters iparameter)
	{
		this.parameter = iparameter;
	}
	
	public class Tracker
	{
		public BSP_Nodes[] data = new BSP_Nodes[100];
		public BSP_Nodes[] nextRound = new BSP_Nodes[100];
	}
	
	public void clearRooms(BSP_Nodes currentNode)
	{
		this.rooms = new BSP_Rectangle[100];
		if(currentNode != root)
		{
			this.clearRooms(currentNode.rightChild);
			this.clearRooms(currentNode.leftChild);
		}
	}
	
	public void getLeafNodes(BSP_Nodes[] data, BSP_Nodes currentNode)
	{
		int k=0;
		if(currentNode != root)
		{
			data[k] = currentNode;
			k++;
		}
		else
		{
			this.getLeafNodes(data, currentNode.rightChild);
			this.getLeafNodes(data, currentNode.leftChild);
		}
	}
	public void generateRoom()
	{
		this.clearRooms(this.root);
		
		for(int z=0;z<this.leafNodes.Length;z++)
		{
			int targetRoomX = getRandomInt(param.minRoomSize,param.maxRoomSize);
			int targetRoomY = getRandomInt(param.minRoomSize,param.maxRoomSize);
			targetRoomX = targetRoomX /100;
			targetRoomY	= targetRoomY / 100;
			float width = (this.myRectangle.width * targetRoomX);
			float height = (this.myRectangle.height * targetRoomY);
			int minX = this.myRectangle.x + 1;
			int minY = this.myRectangle.y + 1;
			int maxX = this.myRectangle.x + this.myRectangle.width - 1 - (int)width;
			int maxY = this.myRectangle.y + this.myRectangle.height -1 - (int)height;
			int x = getRandomInt(minX,maxX);
			int y = getRandomInt(minY,maxY);
			BSP_Rectangle r = new BSP_Rectangle(x,y,(int)width,(int)height);
			
			if(!this.leafNodes[z].contains(r))
				Debug.Log("Failed");
			this.leafNodes[z].addRoom(r);
		}
		this.connectRooms();
	}
	public void connectRooms()
	{
		int i=0;
		this.getLeafNodes(tracker.data, this.root);
		while(tracker.data.Length != 0)
		{
			this.calculateConnections(tracker);

			if(tracker.data.Length == 0)
			{
				i++;
				if(tracker.nextRound.Length == 0)
				{
					break;
				}
				else
				{
					tracker.data = tracker.nextRound;
					tracker.nextRound[i] = null;
				}
			}
		}
	}
	
	public void calculateConnections(Tracker tracker)
	{
		BSP_Nodes node1 = tracker.data[0];
		BSP_Nodes node2 = node1.sister;
		int s=0;
		int r=0;
		if(node2 == null)
		{
			tracker.data[0] = null;
			return;
		}
		
		int si = 1;
		for(si=1;si < tracker.data.Length;si++)
		{
			if(node2.id == tracker.data[si].id) break;
		}
		tracker.data[si] = null;
		tracker.data[0] = null;
		bool sisterIsRight = false;
		if(node1.getem('x') < node2.getem('x')) sisterIsRight = true;
		for(int roList=0; roList<node1.rooms.Length; roList++)
		{
			roomOrder[roList] = roList;
		}
		BSP_Rectangle r1;
		BSP_Rectangle r2;
		for(int rI=0; rI < node1.rooms.Length; rI++)
		{
			int ri = roomOrder[rI];
			r=ri;
			for(int cr=0; cr<node1.rooms.Length; cr++)
			{
				if(ri == cr) continue;
				bool collide = false;
				r1 = node1.rooms[ri].copyRectangle();
				r2 = node2.rooms[cr].copyRectangle();
				if(sisterIsRight && r2.x > r1.x && r2.y < r1.bottom)
				{
					r1.x = 0;
					r2.x = 0;
					if(r1.intersects(r2)) collide = true;
				}
				else if(!sisterIsRight && r2.y > r1.y && r2.x < r1.right)
				{
					r1.y = 0;
					r2.y = 0;
					if(r1.intersects(r2)) collide =true;
				}
				r1.updateRect();
				r2.updateRect();
				if(collide)
				{
					rI++;
					ri=roomOrder[rI];
					cr=0;
					r = ri;
					
				}
				s=rI;
			}
		}
		
		BSP_Rectangle sisterTarget = new BSP_Rectangle(-1,-1,0,0);
		for(int sisterRoom=0; sisterRoom < node2.rooms.Length;sisterRoom++)
		{
			r1= node1.rooms[r].copyRectangle();
			r2 = node2.rooms[sisterRoom].copyRectangle();
			if(sisterIsRight)
				{
					r1.x = 0;
					r2.x = 0;
				}
			else
				{
					r1.y = 0;
					r2.y = 0;
				}
			r1.updateRect();
			r2.updateRect();
			if(r1.intersects(r2))
			{
				if(sisterIsRight)
				{
					if(node2.rooms[sisterRoom].x < sisterTarget.x || sisterTarget.x ==-1) sisterTarget = node2.rooms[sisterRoom].copyRectangle();
				}
				else
				{
					if(node2.rooms[sisterRoom].y < sisterTarget.y || sisterTarget.y == -1) sisterTarget = node2.rooms[sisterRoom].copyRectangle();
				}
			}
		}
		
		BSP_Rectangle connector = new BSP_Rectangle(0,0,0,0);
		if(sisterIsRight)
		{
			connector.x = node1.rooms[r].x + node1.rooms[r].width;
			connector.width = sisterTarget.x - connector.x;
			int minY = Mathf.Max(node1.rooms[r].y, sisterTarget.y);
			int maxY = Mathf.Min(node1.rooms[r].y + node1.rooms[r].height-1, sisterTarget.y + sisterTarget.height -1);
			connector.height = 2;
			connector.y = getRandomInt(minY, maxY);
		}
		else
		{
			connector.y = node1.rooms[r].y + node1.rooms[r].height;
			connector.height = sisterTarget.y - connector.y;
			int minX = Mathf.Max(node1.rooms[r].x, sisterTarget.x);
			int maxX = Mathf.Min(node1.rooms[r].x + node1.rooms[r].width-1, sisterTarget.y + sisterTarget.width -1);
			connector.width = 2;
			connector.x = getRandomInt(minX, maxX);
		}
		connector.updateRect();
		node1.addRoom(connector);
		s = node1.rooms.Length +1;
		if(node1.parent != null) tracker.nextRound[s] = node1.parent;
	}
	public void BSP_Split(BSP_Dungeon dungeon)
	{
			Debug.Log("I saw you hit the button");
			this.BSP_DoSplit();
			Debug.Log("splitCount: " + param.splitCount);
	}
	
	public void BSP_DoSplit()
	{
		this.clearRooms(this.root);
		this.oldNodes = new BSP_Nodes[100];
		this.oldNodes = this.leafNodes;
		this.leafNodes = new BSP_Nodes[100];
		for(int i=0;i<this.oldNodes.Length;i++)
		{
			this.oldNodes[i] = new BSP_Nodes();
			this.oldNodes[i].splitLine = new Line();
			this.oldNodes[i].leftChild = new BSP_Nodes();
			this.oldNodes[i].rightChild = new BSP_Nodes();
			BSP_Nodes n1 = new BSP_Nodes(this.oldNodes[i].getem('x'),this.oldNodes[i].getem('y'),this.oldNodes[i].getem('w'),this.oldNodes[i].getem('h'));
			BSP_Nodes n2 = new BSP_Nodes(this.oldNodes[i].getem('x'),this.oldNodes[i].getem('y'),this.oldNodes[i].getem('w'),this.oldNodes[i].getem('h'));
			n1.parent = this.oldNodes[i];
			n2.parent = this.oldNodes[i];
			n1.sister = n2;
			n2.sister = n1;
			int target = getRandomInt(this.param.minSplit, this.param.maxSplit);
			target = target / 100;
			Point start = new Point(0,0);
            Point end = new Point(0,0);
			
			bool doVerticle = false;
            if(getRandomInt(1,2) == 1) doVerticle = true;
            if(this.oldNodes[i].getem('w')/this.oldNodes[i].getem('h') > 1.3) doVerticle = true;
            if(this.oldNodes[i].getem('h') / this.oldNodes[i].getem('w') > 1.3) doVerticle = false;
            if(doVerticle)
            {
				vertical = true;
               
                BSP_Rectangle r = new BSP_Rectangle(0,0,0,0);
               
                BSP_Rectangle offsetRectangle = new BSP_Rectangle(0, 0, this.oldNodes[i].getem('w'),this.oldNodes[i].getem('h'));                                    

                start.x = offsetRectangle.x + (offsetRectangle.width * target);
                start.y = offsetRectangle.y;
                end.x = start.x;
                end.y = start.y + offsetRectangle.height;
                
                r.x = offsetRectangle.x + this.oldNodes[i].getem('x');
                r.y = offsetRectangle.y + this.oldNodes[i].getem('y');
                r.width = start.x - offsetRectangle.x;
                r.height = offsetRectangle.height;
                n1.addRectangle(r);
				
                r = new BSP_Rectangle(0,0,0,0);
                offsetRectangle = new BSP_Rectangle(0, 0, this.oldNodes[i].getem('w'), this.oldNodes[i].getem('h'));
                
                r.x = start.x + this.oldNodes[i].getem('x');
                r.y = offsetRectangle.y + this.oldNodes[i].getem('y');
                r.width = offsetRectangle.width - start.x;
                r.height = offsetRectangle.height;
                n2.addRectangle(r);
				Debug.Log(start.x);
                start.x += this.oldNodes[i].getem('x');
				Debug.Log(start.x);
                start.y += this.oldNodes[i].getem('y');
                end.x += this.oldNodes[i].getem('x');
                end.y += this.oldNodes[i].getem('y');
				seti(i);
            }
            else
            {
                BSP_Rectangle offsetRectangle = new BSP_Rectangle(0, 0, this.oldNodes[i].getem('w'), this.oldNodes[i].getem('h'));
                                                                       
                start.x = offsetRectangle.x;
                start.y = offsetRectangle.y + (offsetRectangle.height * target);
                end.x = start.x + offsetRectangle.width;
                end.y = start.y;
                
                BSP_Rectangle r = new BSP_Rectangle(0,0,0,0);
                r.x = offsetRectangle.x + this.oldNodes[i].getem('x');
                r.y = offsetRectangle.y + this.oldNodes[i].getem('y');
                r.width = offsetRectangle.width;
                r.height = start.y - offsetRectangle.y;
                n1.addRectangle(r);
                
                offsetRectangle = new BSP_Rectangle(0, 0, this.oldNodes[i].myRectangle.width, this.oldNodes[i].myRectangle.height);
                
                r = new BSP_Rectangle(0,0,0,0);
                
                r.x = offsetRectangle.x + this.oldNodes[i].getem('x');
                r.y = start.y + this.oldNodes[i].getem('y');
                r.width = offsetRectangle.width;
                r.height = offsetRectangle.height - start.y;
                n2.addRectangle(r);
 				start.x += this.oldNodes[i].getem('x');
				Debug.Log(start.x);
                start.y += this.oldNodes[i].getem('y');
                end.x += this.oldNodes[i].getem('x');
                end.y += this.oldNodes[i].getem('y');
				seti(i);
            }
            this.oldNodes[i].splitLine = new Line(start, end);
			this.leafNodes[i] = n1;
			this.leafNodes[i++] = n2;
			this.oldNodes[i--] = n1;
			this.oldNodes[i++] = n2;
			
			
        }
	}
	public void seti(int i)
	{
		globi = i;
	}
	
	public int geti()
	{
		return globi;
	}
	
	public int getRandomInt(int min, int max)
	{
		
		return Random.Range(min, max);
	}
}